/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package DataSelection;

import DataStructures.Property;
import DataStructures.Globals;
import GUI.Utilities;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

/**
 *
 * @author Manuel
 */
public class TaxonomyParser {

    private int noOfConcept1Properties;
    private ArrayList<String> classProperties;

    public TaxonomyParser(){
        classProperties = new ArrayList<String>();
        noOfConcept1Properties = 0;
    }

    public ArrayList<Property> parseTaxonomy(String concept){
        ArrayList<Property> properties = new ArrayList<Property>();
        try {
              DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
              DocumentBuilder builder = factory.newDocumentBuilder();
              InputStream readStream = new ByteArrayInputStream(Utilities.getPage(Globals.TAXONOMIES).getBytes());
              Document xmldocument = builder.parse(new InputSource(readStream));
              org.w3c.dom.Node conceptNode = traverse(xmldocument.getDocumentElement(),concept);
              this.parseNode(conceptNode, properties);
              return properties;

        } catch (ParserConfigurationException ex) {
            ex.printStackTrace();
        } catch (org.xml.sax.SAXException ex){
            ex.printStackTrace();
        } catch (java.io.IOException ex){
            ex.printStackTrace();
        }
        return null;

    }

    
    private void parseNode(org.w3c.dom.Node xmlNode, ArrayList<Property> properties){
        NodeList nl = xmlNode.getChildNodes();


        if(xmlNode.getNodeName().equals("conceptlist") || xmlNode.getNodeName().equals("concept")){

            for(int i = 0;i<nl.getLength();i++){
                this.parseNode(nl.item(i), properties);
            }

        }


        else if(xmlNode.getNodeName().equals("property")){

            Property newProperty = new Property();



            NamedNodeMap attributes = xmlNode.getAttributes();

            String granularity = attributes.getNamedItem("granularity").getNodeValue();
            String  optional = attributes.getNamedItem("optional").getNodeValue();
            String id = attributes.getNamedItem("id").getNodeValue();
            String parentID = xmlNode.getParentNode().getAttributes().getNamedItem("id").getNodeValue();

            newProperty.setName(xmlNode.getNodeName());

            newProperty.setGranularity(granularity);
            if(granularity.equals("class"))
                this.classProperties.add(id);

            newProperty.setName(id);

            newProperty.setConcept(parentID);

            if(optional.equals("true"))
                newProperty.setOptional(true);
            else
                newProperty.setOptional(false);

            org.w3c.dom.Node queryNode = null;
            NodeList children = xmlNode.getChildNodes();
            for(int i = 0;i<children.getLength();i++){
                org.w3c.dom.Node currentNode = children.item(i);
                if(currentNode.getNodeName().equals("query"))
                    queryNode = currentNode;
            }
            if(queryNode == null){
                System.err.println("Error in parsing: Concepts file is not well formed!");
            }
            else{
                Query q = this.parseQueryNode(queryNode);
                newProperty.setQuery(q);

                if(newProperty.hasAllComponents())
                    properties.add(newProperty);

            }


        }
    }

    private org.w3c.dom.Node traverse(org.w3c.dom.Node n, String concept) {

        // find out what type of node this is
        short t = n.getNodeType();
        if (t == Document.ELEMENT_NODE){
            if((n.getNodeName().equals("concept") || n.getNodeName().equals("property"))&& n.getAttributes().getNamedItem("id").getNodeValue().equals(concept)){
                return n;
            }
            NodeList nl = n.getChildNodes();
            if (nl.getLength() == 0) {
                return null;
            }

            for (int i = 0; i < nl.getLength(); i++) {
                org.w3c.dom.Node nd = traverse(nl.item(i), concept);
                if(nd != null)
                    return nd;
            }
        }
        return null;

    }

    private Query parseQueryNode(org.w3c.dom.Node queryNode) {

        Query q = new Query();

        NodeList nl = queryNode.getChildNodes();

        for(int i = 0; i < nl.getLength(); i++){

            org.w3c.dom.Node current = nl.item(i);

            if(current.getNodeName().toLowerCase().equals("select")){
                q.setSelect(current.getTextContent());
            }
            else if(current.getNodeName().toLowerCase().equals("from")){
                q.setFrom(current.getTextContent());
            }
            else if(current.getNodeName().toLowerCase().equals("group")){
                q.setGroup(current.getTextContent());
            }
            else if(current.getNodeName().toLowerCase().equals("where")){
                q.setWhere(current.getTextContent());
            }
            else if(current.getNodeName().toLowerCase().equals("having")){
                q.setHaving(current.getTextContent());
            }

        }

        return q;
    }

    public ArrayList<String> getAllConcepts(){
        ArrayList<String> concepts = new ArrayList<String>();
        try {
              DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
              DocumentBuilder builder = factory.newDocumentBuilder();
              InputStream readStream = new ByteArrayInputStream(Utilities.getPage(Globals.TAXONOMIES).getBytes());
              Document xmldocument = builder.parse(new InputSource(readStream));
              traverse(xmldocument.getDocumentElement(),concepts);
              return concepts;

        } catch (ParserConfigurationException ex) {
            ex.printStackTrace();
        } catch (org.xml.sax.SAXException ex){
            ex.printStackTrace();
        } catch (java.io.IOException ex){
            ex.printStackTrace();
        }
        return null;
    }

    public boolean isOnClassLevel(String property) {
        if(this.classProperties.contains(property.toLowerCase()))
            return true;
        return false;

    }

    public int getNoOfConcept1Properties() {
        return this.noOfConcept1Properties;
    }

    public void setNoOfConcept1Properties(int noOfConcept1Properties) {
        this.noOfConcept1Properties = noOfConcept1Properties;
    }

    private void traverse(org.w3c.dom.Node n, ArrayList<String> concepts) {
        short t = n.getNodeType();
        if (t == Document.ELEMENT_NODE){
            if(n.getNodeName().equals("concept") || n.getNodeName().equals("property")){
                concepts.add(n.getAttributes().getNamedItem("id").getNodeValue());
            }
            NodeList nl = n.getChildNodes();
            if (nl.getLength() == 0) {
                return;
            }

            for (int i = 0; i < nl.getLength(); i++) {
                traverse(nl.item(i), concepts);
            }
        }
        return;
    }



}
